﻿namespace Zhao.Common.Helper
{
    using Microsoft.Extensions.Options;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text.Json;
    using System.Threading.Tasks;

    namespace Zhao.Arena
    {
        /// <summary>
        /// 节假日检查器，用于判断指定日期是否为节假日或周末
        /// </summary>
        public class HolidayChecker
        {
            // 节假日配置文件路径
            private readonly string _holidayFilePath;

            // 存储节假日日期的哈希集合，键为"yyyy-MM-dd"格式的日期字符串
            private static HashSet<string> _holidaySet;

            // 标记是否已加载节假日数据
            private static bool _isLoaded = false;

            // 用于线程同步的锁对象
            private static readonly object _lock = new();

            /// <summary>
            /// 初始化节假日检查器
            /// </summary>
            /// <param name="options">节假日配置选项</param>
            public HolidayChecker(IOptions<HolidaySettings> options)
            {
                // 获取项目根目录（不管你是开发环境、测试还是发布环境）
                var rootPath = AppContext.BaseDirectory;

                // 将相对路径与根目录拼接
                _holidayFilePath = Path.Combine(rootPath, options.Value.HolidayFilePath);
            }

            /// <summary>
            /// 确保节假日数据已加载
            /// 使用双重检查锁定模式确保线程安全且只加载一次
            /// </summary>
            private void EnsureLoaded()
            {
                // 快速检查是否已加载，避免不必要的锁竞争
                if (_isLoaded) return;

                // 加锁确保在多线程环境下只有一个线程执行加载操作
                lock (_lock)
                {
                    // 再次检查，防止在等待锁的过程中其他线程已完成加载
                    if (_isLoaded) return;

                    // 检查配置文件是否存在
                    if (File.Exists(_holidayFilePath))
                    {
                        // 读取JSON文件内容
                        var json = File.ReadAllText(_holidayFilePath);

                        // 反序列化为日期字典（键为日期字符串，值为是否为节假日的布尔值）
                        var dict = JsonSerializer.Deserialize<Dictionary<string, bool>>(json);

                        // 筛选出标记为节假日的日期并转换为哈希集合
                        _holidaySet = dict.Where(kv => kv.Value).Select(kv => kv.Key).ToHashSet();
                    }

                    // 标记为已加载
                    _isLoaded = true;
                }
            }

            /// <summary>
            /// 异步检查指定日期是否为节假日或周末
            /// </summary>
            /// <param name="date">要检查的日期，若为null则使用当前日期</param>
            /// <returns>是否为节假日或周末的布尔值</returns>
            public Task<bool> IsHolidayOrWeekend(DateTime? date)
            {
                // 确保节假日数据已加载
                EnsureLoaded();

                // 获取要检查的日期（若未提供则使用当前日期）
                var dt = date ?? DateTime.Now;

                // 格式化为"yyyy-MM-dd"字符串作为键
                var key = dt.ToString("yyyy-MM-dd");

                // 检查是否为节假日
                bool isHoliday = _holidaySet != null && _holidaySet.Contains(key);

                // 检查是否为周末（周六或周日）
                bool isWeekend = dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday;

                // 返回异步任务结果
                return Task.FromResult(isHoliday || isWeekend);
            }
        }

    }

}
